
`include "common_header.verilog"

//  *************************************************************************
//  File : top_pause_64
//  *************************************************************************
//  This program is controlled by a written license agreement.
//  Unauthorized reproduction or use is expressly prohibited.
//  Copyright (c) 2014 MorethanIP
//  Muenchner Strasse 199, 85757 Karlsfeld, Germany
//  info@morethanip.com
//  http://www.morethanip.com
//  *************************************************************************
//  Designed by : Thomas Schrobenhauser
//  info@morethanip.com
//  *************************************************************************
//  Description : Flow Control (Pause/PFC) Interface for 64-bit Datapath
//  Version     : $Id: top_pause_64.v,v 1.8 2016/08/09 12:20:01 dp Exp $
//  *************************************************************************

module top_pause_64 (
   reset_txclk,
   reset_rxclk,
   tx_clk,
   tx_clk_ena,
   rx_clk,
   tx_data_ff,
   tx_sop_ff,
   tx_eop_ff,
   tx_sav_ff,
   tx_empty_ff,
   tx_rden_ff,
   tx_rden_sop_ff,
   tx_rden_sop_pause,
   tx_data_err_ff,
   tx_preamble_ff,
   tx_stat_empty_ff,
   tx_stat_mod_ff,
   tx_stat_err_ff,
   tx_stat_crc_ff,
   tx_stat_id_ff,
   tx_stat_ts_frm_ff,
   tx_data_mac,
   tx_sop_mac,
   tx_eop_mac,
   tx_sav_mac,
   tx_empty_mac,
   tx_rden_mac,
   tx_rden_sop_mac,
   tx_data_err_mac,
   tx_preamble_mac,
   tx_stat_empty_mac,
   tx_stat_mod_mac,
   tx_stat_err_mac,
   tx_stat_crc_mac,
   tx_stat_id_mac,
   tx_stat_ts_frm_mac,
   tx_stat_pgen_mac,
   rx_data_ff,
   rx_sop_ff,
   rx_eop_ff,
   rx_mod_ff,
   rx_wren_ff,
   rx_dval_ff,
   rx_afull_ff,
   rx_empty_st_ff,
   rx_preamble_ff,
   rx_stat_wren_ff,
   rx_stat_data_ff,
   rx_data_mac,
   rx_sop_mac,
   rx_eop_mac,
   rx_mod_mac,
   rx_wren_mac,
   rx_dval_mac,
   rx_afull_mac,
   rx_empty_st_mac,
   rx_preamble_mac,
   rx_stat_wren_mac,
   rx_stat_data_mac,
   tx_pfc_xoff,
   tx_pfc_ack,
   rx_pfc_xoff,
   tx_enable,
   rx_enable,
   mac_addr,
   pause_fwd,
   rx_pause_bypass,
   pause_ignore,
   cmd_frm_ena,
   pfc_mode,
   pause_pfc_cmptbl,
   cl_pause_quanta,
   cl_pause_thresh,
   qmodeidle8x,
   tx_flush
   );

parameter       RX_STAT_DAT_WIDTH_64 = 25;
`include "mtip_40geth_pack_package.verilog"

input   reset_txclk;                            //  Active High reset for tx_clk domain
input   reset_rxclk;                            //  Active High reset for rx_clk domain
input   tx_clk;                                 //  XLGMII Transmit clock
input   tx_clk_ena;                             //  XLGMII Transmit clock enable
input   rx_clk;                                 //  XLGMII Receive clock
input   [63:0] tx_data_ff;                      //  Transmit Data from FIFO
input   tx_sop_ff;                              //  Transmit Start of Packet
input   tx_eop_ff;                              //  Transmit End of Packet
input   tx_sav_ff;                              //  Transmit Data Section Available in FIFO
input   tx_empty_ff;                            //  Transmit Data FIFO Empty
output  tx_rden_ff;                             //  Transmit Data FIFO Read enable (FIFO to react with 1 cycle latency)
output  tx_rden_sop_ff;                         //  Transmit reads first word from FIFO
output  tx_rden_sop_pause;                      //  Transmit reads first word from internally generated pause frame
input   tx_data_err_ff;                         //  Memory read error, need to corrupt frame
input   [55:0] tx_preamble_ff;                  //  Transmit Preamble
input   tx_stat_empty_ff;                       //  Transmit Status FIFO Word Empty
input   [2:0] tx_stat_mod_ff;                   //  2:0 Last word modulo; valid with eop
input   tx_stat_err_ff;                         //  3: Error indication from FIFO; valid with eop
input   tx_stat_crc_ff;                         //  4: CRC append indication from FIFO; valid with eop
input   [TSID_WIDTH-1:0] tx_stat_id_ff;         //  Frame identifier
input   tx_stat_ts_frm_ff;                      //  Store timestamp command
output  [63:0] tx_data_mac;                     //  Transmit Data from FIFO
output  tx_sop_mac;                             //  Transmit Start of Packet
output  tx_eop_mac;                             //  Transmit End of Packet
output  tx_sav_mac;                             //  Transmit Data Section Available in FIFO
output  tx_empty_mac;                           //  Transmit Data FIFO Empty
input   tx_rden_mac;                            //  Transmit Data FIFO Read enable (FIFO to react with 1 cycle latency)
input   tx_rden_sop_mac;                        //  Transmit reads first word from FIFO
output  tx_data_err_mac;                        //  Memory read error, need to corrupt frame
output  [55:0] tx_preamble_mac;                 //  Transmit Preamble
output  tx_stat_empty_mac;                      //  Transmit Status FIFO Word Empty
output  [2:0] tx_stat_mod_mac;                  //  2:0 Last word modulo; valid with eop
output  tx_stat_err_mac;                        //  3: Error indication from FIFO; valid with eop
output  tx_stat_crc_mac;                        //  4: CRC append indication from FIFO; valid with eop
output  [TSID_WIDTH-1:0] tx_stat_id_mac;        //  Frame identifier
output  tx_stat_ts_frm_mac;                     //  Store timestamp command
output  tx_stat_pgen_mac;                       //  Internally generated pause frame
output  [63:0] rx_data_ff;                      //  Receive Data to FIFO
output  rx_sop_ff;                              //  Receive Start of Packet
output  rx_eop_ff;                              //  Receive End of Packet
output  [2:0] rx_mod_ff;                        //  Receive last word modulo
output  rx_wren_ff;                             //  Receive Data FIFO write enable
output  rx_dval_ff;                             //  Receive Data valid
input   rx_afull_ff;                            //  Receive Data FIFO almost full
input   rx_empty_st_ff;                         //  RX FIFO empty (data+status)
output  [55:0] rx_preamble_ff;                  //  Receive frame preamble (stable from sop)
output  rx_stat_wren_ff;                        //  Receive Status FIFO write enable
output  [RX_STAT_DAT_WIDTH_64-1:0] rx_stat_data_ff;                 //  Receive Frame Status & Error indications
input   [63:0] rx_data_mac;                     //  Receive Data to FIFO
input   rx_sop_mac;                             //  Receive Start of Packet
input   rx_eop_mac;                             //  Receive End of Packet
input   [2:0] rx_mod_mac;                       //  Receive last word modulo
input   rx_wren_mac;                            //  Receive Data FIFO write enable
input   rx_dval_mac;                            //  Receive Data valid
output  rx_afull_mac;                           //  Receive Data FIFO almost full
output  rx_empty_st_mac;                        //  RX FIFO empty (data+status)
input   [55:0] rx_preamble_mac;                 //  Receive frame preamble (stable from sop)
input   rx_stat_wren_mac;                       //  Receive Status FIFO write enable
input   [RX_STAT_DAT_WIDTH_64-1:0] rx_stat_data_mac;                //  Receive Frame Status & Error indications
input   [7:0] tx_pfc_xoff;                      //  Transmit Flow Control Generate (txclk)
output  tx_pfc_ack;                             //  Transmit Flow Control Acknowledge (Generate was sampled) (txclk)
output  [7:0] rx_pfc_xoff;                      //  Received pause indicating pause on (rxclk)
input   tx_enable;                              //  Enable MAC transmit path
input   rx_enable;                              //  Enable MAC receive path
input   [47:0] mac_addr;                        //  Device Ethernet MAC address
input   pause_fwd;                              //  Forward Pause Frames to Application
input   rx_pause_bypass;                        //  if 1 the pause frame removal datapath function is bypassed
input   pause_ignore;                           //  Ignore Pause Frames Quantas
input   cmd_frm_ena;                            //  Enable Command Frames
input   pfc_mode;                               //  Priority flow control enabled
input   pause_pfc_cmptbl;                       //  Link Pause Compatibility with PFC mode enable
input   [(8*16)-1:0] cl_pause_quanta;           //  Class 0..7 PFC Quanta value
input   [(8*16)-1:0] cl_pause_thresh;           //  Threshold for Class 0..7 Refresh PFC Frame
input   qmodeidle8x;                            //  consider clock-enable during IDLE to be 8x faster (i.e. byte clock instead word clock)
input   tx_flush;                               //  Flush egress pipeline

wire    tx_rden_ff;
wire    tx_rden_sop_ff;
wire    tx_rden_sop_pause;
wire    [63:0] tx_data_mac;
wire    tx_sop_mac;
wire    tx_eop_mac;
wire    tx_sav_mac;
wire    tx_empty_mac;
wire    tx_data_err_mac;
wire    [55:0] tx_preamble_mac;
wire    tx_stat_empty_mac;
wire    [2:0] tx_stat_mod_mac;
wire    tx_stat_err_mac;
wire    tx_stat_crc_mac;
wire    [TSID_WIDTH-1:0] tx_stat_id_mac;
wire    tx_stat_ts_frm_mac;
wire    tx_stat_pgen_mac;
wire    [63:0] rx_data_ff;
wire    rx_sop_ff;
wire    rx_eop_ff;
wire    [2:0] rx_mod_ff;
wire    rx_wren_ff;
wire    rx_dval_ff;
wire    [55:0] rx_preamble_ff;
wire    rx_stat_wren_ff;
wire    [RX_STAT_DAT_WIDTH_64-1:0] rx_stat_data_ff;
wire    rx_afull_mac;
wire    rx_empty_st_mac;
wire    tx_pfc_ack;
wire    [7:0] rx_pfc_xoff;

wire    tx_enable_t;
wire    pfc_mode_t;
wire    tx_flush_t;
wire    rx_enable_r;
wire    pause_fwd_r;
wire    rx_pause_bypass_r;
wire    pause_ignore_r;
wire    cmd_frm_ena_r;
wire    pfc_mode_r;
wire    pause_pfc_cmptbl_r;
wire    tx_flush_r;
wire    pfc_mode_rcv_ctl;
wire    [135:0] pause_quant_val;
wire    pause_quant_avb;
wire    [7:0] rx_pfc_xoff_int;
wire    pause_gen;
wire    [63:0] pause_gen_data;
wire    [2:0] pause_gen_wcnt;
wire    pause_wait_t;           //  indicate tx should pause (txclk)
wire    pause_cnt_dec_t;        //  MAC tx statemachine is paused, pause counter may decrement now (txclk)
wire    qtime_t;                //  pulse when pause time of 1 expired (512 bits) (txclk)
wire    qtime_t_run;            //  timer is enabled, should generate pulses (txclk)
wire    qmodeidle8x_t;          //  consider clock-enable during IDLE to be 8x faster (i.e. byte clock instead word clock)
wire    qinc8_t;                //  increment tx pause timer by 8
wire    qtime_r;                //  pulse when pause time of 1 expired (512 bits) (rxclk)
wire    qtime_r_run;            //  timer is enabled, should generate pulses (rxclk)
wire    qmodeidle8x_r;          //  consider clock-enable during IDLE to be 8x faster (i.e. byte clock instead word clock)
wire    qinc8_r;                //  increment rx pause timer by 8

// ----------------------
// Clock domain crossings
// ----------------------

// into TX line clock domain
mtip_xsync #(4) U_TXSYNC (
          .data_in(             {qmodeidle8x, tx_enable, pfc_mode, tx_flush}),
          .reset(reset_txclk),
          .clk(tx_clk),
          .data_s(              {qmodeidle8x_t, tx_enable_t, pfc_mode_t, tx_flush_t}));





// into RX line clock domain
mtip_xsync #(9) U_RXSYNC (
          .data_in(             {qmodeidle8x, rx_enable, pause_fwd, rx_pause_bypass, pause_ignore, cmd_frm_ena,
                                 pfc_mode, pause_pfc_cmptbl, tx_flush}),
          .reset(reset_rxclk),
          .clk(rx_clk),
          .data_s(              {qmodeidle8x_r, rx_enable_r, pause_fwd_r, rx_pause_bypass_r, pause_ignore_r, cmd_frm_ena_r,
                                 pfc_mode_r, pause_pfc_cmptbl_r, tx_flush_r}));


// ----------------
// Receive Datapath
// ----------------

pause_rxdp_64 

#(
        // use instance parameters instead package parameters
          .RX_STAT_DAT_WIDTH_64(RX_STAT_DAT_WIDTH_64)     // RX Frame Status
                                                        )


U_PRXDP (
          .reset_rxclk(reset_rxclk),
          .rx_clk(rx_clk),
          .rx_data_ff(rx_data_ff),
          .rx_sop_ff(rx_sop_ff),
          .rx_eop_ff(rx_eop_ff),
          .rx_mod_ff(rx_mod_ff),
          .rx_wren_ff(rx_wren_ff),
          .rx_dval_ff(rx_dval_ff),
          .rx_afull_ff(rx_afull_ff),
          .rx_empty_st_ff(rx_empty_st_ff),
          .rx_preamble_ff(rx_preamble_ff),
          .rx_stat_wren_ff(rx_stat_wren_ff),
          .rx_stat_data_ff(rx_stat_data_ff),
          .rx_data_mac(rx_data_mac),
          .rx_sop_mac(rx_sop_mac),
          .rx_eop_mac(rx_eop_mac),
          .rx_mod_mac(rx_mod_mac),
          .rx_wren_mac(rx_wren_mac),
          .rx_dval_mac(rx_dval_mac),
          .rx_afull_mac(rx_afull_mac),
          .rx_empty_st_mac(rx_empty_st_mac),
          .rx_preamble_mac(rx_preamble_mac),
          .rx_stat_wren_mac(rx_stat_wren_mac),
          .rx_stat_data_mac(rx_stat_data_mac),
          .pause_quant_val(pause_quant_val),
          .pause_quant_avb(pause_quant_avb),
          .mac_addr(mac_addr),
          .pause_fwd(pause_fwd_r),
          .rx_pause_bypass(rx_pause_bypass_r),
          .pause_ignore(pause_ignore_r),
          .cmd_frm_ena(cmd_frm_ena_r),
          .pfc_mode(pfc_mode_r)
          );


// Receive Pause Handling

pfc_rcv_ctl U_PRCV (
          .reset_rxclk(reset_rxclk),
          .xgmii_rxclk(rx_clk),
          .xgmii_rxclk_ena(rx_dval_mac),
          .rx_enable(rx_enable_r),
          .pfc_mode_r(pfc_mode_rcv_ctl),
          .qtime_r(qtime_r),
          .qtime_run(qtime_r_run),
          .pause_quant_val(pause_quant_val),
          .pause_quant_avb(pause_quant_avb),
          .rx_pfc_xoff(rx_pfc_xoff_int),        //  current status
          .reset_txclk(reset_txclk),
          .xgmii_txclk(tx_clk),
          .xgmii_txclk_ena(tx_clk_ena),
          .pause_wait_t(pause_wait_t),          //  to tx, should pause
          .pause_cnt_dec_t(pause_cnt_dec_t));   //  from tx, its idle


assign pfc_mode_rcv_ctl = pfc_mode_r | pause_pfc_cmptbl_r;

assign rx_pfc_xoff = tx_flush_r == 1'b 0 ? rx_pfc_xoff_int : 8'h 00;


// -----------------
// Transmit Datapath
// -----------------

pause_txdp_64 U_PTXDP (
          .reset_txclk(reset_txclk),
          .tx_clk(tx_clk),
          .tx_clk_ena(tx_clk_ena),
          .tx_data_ff(tx_data_ff),
          .tx_sop_ff(tx_sop_ff),
          .tx_eop_ff(tx_eop_ff),
          .tx_sav_ff(tx_sav_ff),
          .tx_empty_ff(tx_empty_ff),
          .tx_rden_ff(tx_rden_ff),
          .tx_rden_sop_ff(tx_rden_sop_ff),
          .tx_rden_sop_pause(tx_rden_sop_pause),
          .tx_data_err_ff(tx_data_err_ff),
          .tx_preamble_ff(tx_preamble_ff),
          .tx_stat_empty_ff(tx_stat_empty_ff),
          .tx_stat_mod_ff(tx_stat_mod_ff),
          .tx_stat_err_ff(tx_stat_err_ff),
          .tx_stat_crc_ff(tx_stat_crc_ff),
          .tx_stat_id_ff(tx_stat_id_ff),
          .tx_stat_ts_frm_ff(tx_stat_ts_frm_ff),
          .tx_data_mac(tx_data_mac),
          .tx_sop_mac(tx_sop_mac),
          .tx_eop_mac(tx_eop_mac),
          .tx_sav_mac(tx_sav_mac),
          .tx_empty_mac(tx_empty_mac),
          .tx_rden_mac(tx_rden_mac),
          .tx_rden_sop_mac(tx_rden_sop_mac),
          .tx_data_err_mac(tx_data_err_mac),
          .tx_preamble_mac(tx_preamble_mac),
          .tx_stat_empty_mac(tx_stat_empty_mac),
          .tx_stat_mod_mac(tx_stat_mod_mac),
          .tx_stat_err_mac(tx_stat_err_mac),
          .tx_stat_crc_mac(tx_stat_crc_mac),
          .tx_stat_id_mac(tx_stat_id_mac),
          .tx_stat_ts_frm_mac(tx_stat_ts_frm_mac),
          .tx_stat_pgen_mac(tx_stat_pgen_mac),
          .pause_gen(pause_gen),
          .pause_gen_data(pause_gen_data),
          .pause_gen_wcnt(pause_gen_wcnt),
          .pause_wait_t(pause_wait_t),
          .pause_cnt_dec_t(pause_cnt_dec_t),
          .tx_enable(tx_enable_t),
          .tx_flush(tx_flush_t)
          );


// Transmit Pause Frame Generator

pfc_xmit_ctl_64 U_PXMT (
          .reset_txclk(reset_txclk),
          .xgmii_txclk(tx_clk),
          .xgmii_txclk_ena(tx_clk_ena),
          .tx_enable(tx_enable_t),
          .qtime_t(qtime_t),
          .qtime_t_run(qtime_t_run),
          .pause_gen(pause_gen),
          .pause_gen_data(pause_gen_data),
          .pause_gen_wcnt(pause_gen_wcnt),
          .pfc_mode(pfc_mode_t),                //  sync'ed
          .mac_addr(mac_addr),
          .cl_pause_quanta(cl_pause_quanta),
          .cl_pause_thresh(cl_pause_thresh),
          .tx_pfc_xoff(tx_pfc_xoff),
          .tx_pfc_ack(tx_pfc_ack),
          .tsv_stat_pfc());


// ------------------
// Pause Quanta Timer
// ------------------

// operates in tx clock domain

        // With a GMII converter: increment by 8 only when MAC processes words, otherwise (IDLE) increment by 1 only. 
assign  qinc8_t = ~qmodeidle8x_t | tx_rden_mac;

pause_qtimer_64 U_TTX (
          .reset(reset_txclk),
          .clk(tx_clk),
          .clk_ena(tx_clk_ena),
          .qinc8(qinc8_t),
          .qtime(qtime_t),
          .qtime_run(qtime_t_run));

// operates in RX clock domain

        // With a GMII converter: increment by 8 only when MAC processes words (dval=wren=1), otherwise (IDLE) increment by 1 only. 
assign  qinc8_r = ~qmodeidle8x_r | (rx_dval_mac & rx_wren_mac);

pause_qtimer_64 U_TRX (
          .reset(reset_rxclk),
          .clk(rx_clk),
          .clk_ena(rx_dval_mac),
          .qinc8(qinc8_r),
          .qtime(qtime_r),
          .qtime_run(qtime_r_run));


endmodule // module top_pause_64
